package org.Yiran.timetale_re.util.cooldown;

import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.util.INBTSerializable;
import net.minecraftforge.registries.ForgeRegistries;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 冷却追踪器
 * <p>
 * 用于追踪每个玩家的冷却时间，支持基于物品和基于标识符的冷却管理。
 * 实现了NBT序列化接口，可以保存和加载冷却数据。
 * </p>
 * 
 * @author Yiran
 * @version 1.0
 */
public class CooldownTracker implements INBTSerializable<CompoundTag> {
    
    // ==================== 数据存储 ====================
    
    /**
     * 存储冷却时间的映射
     * <p>
     * 键为冷却键，值为冷却结束时间（游戏刻）。
     * </p>
     */
    private final Map<String, Long> cooldowns = new HashMap<>();

    // ==================== 玩家标识 ====================
    
    /**
     * 玩家UUID
     * <p>
     * 用于标识该冷却追踪器属于哪个玩家。
     * </p>
     */
    private final UUID playerId;

    // ==================== 构造函数 ====================

    /**
     * 构造函数
     * <p>
     * 创建一个新的冷却追踪器实例，关联指定的玩家。
     * </p>
     * 
     * @param playerId 玩家UUID
     */
    public CooldownTracker(UUID playerId) {
        this.playerId = playerId;
    }

    // ==================== 冷却检查方法 ====================

    /**
     * 检查指定的冷却是否已结束
     * <p>
     * 检查指定冷却键的冷却是否已经结束。
     * 如果冷却键不存在或当前时间已超过冷却结束时间，则认为冷却已结束。
     * </p>
     * 
     * @param key 冷却键
     * @param currentTime 当前游戏时间（tick）
     * @return 如果冷却已结束返回true，否则返回false
     */
    public boolean isCooldownOver(String key, long currentTime) {
        return !cooldowns.containsKey(key) || currentTime >= cooldowns.get(key);
    }

    // ==================== 冷却设置方法 ====================

    /**
     * 设置冷却时间
     * <p>
     * 为指定冷却键设置冷却结束时间。
     * </p>
     * 
     * @param key 冷却键
     * @param endTime 冷却结束时间（tick）
     */
    public void setCooldown(String key, long endTime) {
        cooldowns.put(key, endTime);
    }

    // ==================== 冷却时间查询方法 ====================

    /**
     * 获取剩余冷却时间
     * <p>
     * 获取指定冷却键的剩余冷却时间。
     * 如果冷却键不存在，则返回0。
     * </p>
     * 
     * @param key 冷却键
     * @param currentTime 当前游戏时间（tick）
     * @return 剩余冷却时间（tick），如果无冷却则返回0
     */
    public long getRemainingCooldown(String key, long currentTime) {
        if (!cooldowns.containsKey(key)) {
            return 0;
        }
        long remaining = cooldowns.get(key) - currentTime;
        return Math.max(0, remaining);
    }

    // ==================== 冷却移除方法 ====================

    /**
     * 移除冷却
     * <p>
     * 从冷却映射中移除指定冷却键的冷却记录。
     * </p>
     * 
     * @param key 冷却键
     */
    public void removeCooldown(String key) {
        cooldowns.remove(key);
    }

    // ==================== 冷却键生成方法 ====================

    /**
     * 获取冷却键，支持基于物品NBT区分
     * <p>
     * 根据冷却类别和物品堆生成唯一的冷却键。
     * 如果物品有NBT标签，则将其包含在冷却键中以区分不同的物品变体。
     * </p>
     * 
     * @param category 冷却类别
     * @param itemStack 物品堆，用于生成基于NBT的键
     * @return 唯一的冷却键
     */
    public static String getCooldownKey(String category, ItemStack itemStack) {
        String baseKey = category + ":" + ForgeRegistries.ITEMS.getKey(itemStack.getItem());
        
        // 如果物品有NBT标签，则将其包含在冷却键中
        if (itemStack.hasTag()) {
            CompoundTag tag = itemStack.getTag();
            if (tag != null) {
                // 使用NBT的哈希码作为区分依据
                baseKey += ":" + tag.hashCode();
            }
        }
        
        return baseKey;
    }

    /**
     * 获取冷却键（无物品区分）
     * <p>
     * 根据冷却类别和标识符生成唯一的冷却键。
     * </p>
     * 
     * @param category 冷却类别
     * @param identifier 标识符
     * @return 唯一的冷却键
     */
    public static String getCooldownKey(String category, String identifier) {
        return category + ":" + identifier;
    }

    // ==================== NBT序列化方法 ====================

    /**
     * 序列化为NBT标签
     * <p>
     * 将冷却追踪器中的所有冷却数据序列化为NBT标签，用于保存到世界数据中。
     * </p>
     * 
     * @return 包含冷却数据的NBT标签
     */
    @Override
    public CompoundTag serializeNBT() {
        CompoundTag tag = new CompoundTag();
        ListTag cooldownList = new ListTag();

        for (Map.Entry<String, Long> entry : cooldowns.entrySet()) {
            CompoundTag cooldownTag = new CompoundTag();
            cooldownTag.putString("Key", entry.getKey());
            cooldownTag.putLong("EndTime", entry.getValue());
            cooldownList.add(cooldownTag);
        }

        tag.put("Cooldowns", cooldownList);
        return tag;
    }

    /**
     * 从NBT标签反序列化
     * <p>
     * 从NBT标签中加载冷却数据，用于从世界数据中恢复冷却状态。
     * </p>
     * 
     * @param tag 包含冷却数据的NBT标签
     */
    @Override
    public void deserializeNBT(CompoundTag tag) {
        cooldowns.clear();
        ListTag cooldownList = tag.getList("Cooldowns", Tag.TAG_COMPOUND);

        for (int i = 0; i < cooldownList.size(); i++) {
            CompoundTag cooldownTag = cooldownList.getCompound(i);
            String key = cooldownTag.getString("Key");
            long endTime = cooldownTag.getLong("EndTime");
            cooldowns.put(key, endTime);
        }
    }

    // ==================== 获取方法 ====================

    /**
     * 获取玩家ID
     * <p>
     * 获取与该冷却追踪器关联的玩家UUID。
     * </p>
     * 
     * @return 玩家UUID
     */
    public UUID getPlayerId() {
        return playerId;
    }
}